/**
	License:		Artistic license 2.0 (see license.txt, also available online at http://www.perlfoundation.org/artistic_license_2_0)
	Authors:		OrbitalLab (http://www.orbitallab.ru/moonglide/), 2007-2009

	File:			GMSMeshIO.d
	Description:	mesh loading for *.gms files
	Date:			9.12.2007 by Jurec
*/
module moonglide.resources.io.mesh.gms.GMSMeshIO;

import
	tango.text.Util,
	tango.io.stream.Lines,

	moonglide.resources.io.mesh.MeshIO,
	moonglide.resources.resproc.mesh.ResPMesh,
	moonglide.resources.Management;

alias tango.text.Util.split!(char) ssplit;


//================================================================
/// mesh io provider class
//================================================================
class CMeshGMSIOProvider : CMeshIOProvider
{
	protected:
		Lines!(char) 		_lineReader;
		char[][]			_splitted;

		void FixIndxs(
			in Vector3f[]	Vertices,
			in Vector3f[]	Normals,
			in Vector2f[]	TexVerts,
			in uint[]		Faces,
			in uint[]		TexFaces,
			out Vector3f[]	finalvertices,
			out Vector3f[]	finalnorm,
			out Vector2f[]	finaltexverts,
			out uint[]		finalindices )
		{
			uint Face3 = Faces.length / 3;

			if( Vertices.length >= TexVerts.length )
			{
				finalvertices.length	= Vertices.length;
				finalnorm.length		= Normals.length;
				finalindices.length		= Faces.length;

				finalvertices[] = Vertices.dup;
				finalnorm[]		= Normals.dup;
				finalindices[]	= Faces.dup;

				finaltexverts.length 	= Faces.length ;

				for( uint i = 0; i < Face3; ++i )
				{
					finaltexverts [ Faces[i*3+0] ] = TexVerts[ TexFaces[i*3+0] ];
					finaltexverts [ Faces[i*3+1] ] = TexVerts[ TexFaces[i*3+1] ];
					finaltexverts [ Faces[i*3+2] ] = TexVerts[ TexFaces[i*3+2] ];
				}
			}
			else
			{
				finaltexverts.length = TexVerts.length;
				finalindices.length = TexFaces.length;

				finaltexverts[]	= TexVerts.dup;
				finalindices[] 	= TexFaces.dup;

				finalvertices.length 	= TexVerts.length ;
				finaltexverts.length 	= TexVerts.length ;
				finalnorm.length 		= TexVerts.length ;

				for( uint i = 0; i < Face3; ++i )
				{
					finalvertices[ TexFaces[i*3+0] ] = Vertices[ Faces[i*3+0] ];
					finalvertices[ TexFaces[i*3+1] ] = Vertices[ Faces[i*3+1] ];
					finalvertices[ TexFaces[i*3+2] ] = Vertices[ Faces[i*3+2] ];

					finalnorm[ TexFaces[i*3+0]] = Normals[ Faces[i*3+0] ];
					finalnorm[ TexFaces[i*3+1]] = Normals[ Faces[i*3+1] ];
					finalnorm[ TexFaces[i*3+2]] = Normals[ Faces[i*3+2] ];
				}
			}

		}

		void ReadTriMesh( char[] name, ref CResMesh M1 )
		{
			char[] _tempString;
			_lineReader.readln( _tempString );// numverts numfaces numtverts

			uint numverts, numfaces, numtverts;

			_lineReader.readln( _tempString );
			_splitted = ssplit( _tempString, " " );

			numverts = strToInt( _splitted[0] );
			numfaces = strToInt( _splitted[1] );
			numtverts = strToInt( _splitted[2] );

			_lineReader.readln( _tempString );// Mesh vertices:

			Vector3f[]	Vertex;
			uint[]		Indexes;
			Vector3f[]	Normal;
			Vector2f[]	TexCoord;
			uint[]		texInd;

			Vertex.length	=	numverts;
			Indexes.length	=	numfaces*3;
			Normal.length	=	numverts;
			TexCoord.length	=	numtverts;
			texInd.length	=	numfaces*3;

			float X,Y,Z;

			Matrix33f conv = Matrix33f.rotationX( -PI/2 );

			foreach( inout Vector3f ver; Vertex )
			{
				_lineReader.readln( _tempString );
				_splitted = ssplit( _tempString, " " );

				X = strToFloat( _splitted[0] );
				Y = strToFloat( _splitted[1] );
				Z = strToFloat( _splitted[2] );

				ver = conv * Vector3f ( X,Y,Z );
			}

			_lineReader.readln( _tempString );// end vertices
			_lineReader.readln( _tempString );// Mesh faces:

			for( uint vert = 0; vert < numfaces; ++vert )
			{
				_lineReader.readln( _tempString );
				_splitted = ssplit( _tempString, " " );

				Indexes[vert*3] = strToInt( _splitted[0] );
				Indexes[vert*3+1] = strToInt( _splitted[1] );
				Indexes[vert*3+2] = strToInt( _splitted[2] );

			}

			_lineReader.readln( _tempString );// end faces
			_lineReader.readln( _tempString );// smooth normals

			foreach( inout Vector3f nor; Normal )
			{
				_lineReader.readln( _tempString );
				_splitted = ssplit( _tempString, " " );

				X = strToFloat( _splitted[0] );
				Y = strToFloat( _splitted[1] );
				Z = strToFloat( _splitted[2] );

				nor = conv * Vector3f( X,Y,Z );
			}

			_lineReader.readln( _tempString );// end smooth normals
			_lineReader.readln( _tempString );// Mesh texcoords:

			foreach( inout Vector2f tcoor; TexCoord )
			{
				_lineReader.readln( _tempString );
				_splitted = ssplit( _tempString, " " );

				X = strToFloat( _splitted[0] );
				Y = strToFloat( _splitted[1] );

				tcoor = Vector2f ( X,Y );
			}

			_lineReader.readln( _tempString );// end texcoords
			_lineReader.readln( _tempString );// Mesh texcoords indxs

			for( uint vert = 0; vert < numfaces; ++vert )
			{
				_lineReader.readln( _tempString );
				_splitted = ssplit( _tempString, " " );

				texInd[vert*3] = strToInt( _splitted[0] );
				texInd[vert*3+1] = strToInt( _splitted[1] );
				texInd[vert*3+2] = strToInt( _splitted[2] );

			}

			_lineReader.readln( _tempString );// end texcoords indx
			_lineReader.readln( _tempString );// end mesh

			FixIndxs(Vertex,
					 Normal,
					 TexCoord,
					 Indexes,
					 texInd,
					 M1.fields["Vertex"].data.Vec3,
					 M1.fields["Normal"].data.Vec3,
					 M1.fields["TexCoord"].data.Vec2,
					 M1.fields["Index"].data.UInt);

			//M1.Tangent.resize( numverts );
			//M1.BiNormal.resize( numverts );

			genMeshTangentSpace( M1 );
		}


		void ReadObj( char[] name, ref CResMesh mesh )
		{
			char[]
				trimesh = "TriMesh()",
				_tempString,
				idName,
				typeName;

			_lineReader.readln( _tempString );
			_lineReader.readln( _tempString );
			_splitted = ssplit( _tempString, " " );

			float
				aa = strToFloat( _splitted[0] ),
				bb = strToFloat( _splitted[1] ),
				cc = strToFloat( _splitted[2] );

			_lineReader.readln( _tempString );
			idName = _tempString;

			_lineReader.readln( _tempString );
			typeName = _tempString;

			if( typeName == trimesh )
				ReadTriMesh( name, mesh );
		}

	public:
		void Load( char[] extension, ref IResource res, InputStream stream, uint streamsize )
		{
			if( _lineReader !is null )
				delete _lineReader;

			_lineReader = new Lines!(char)( stream );

			char[]
				_tempString,
				newobj = "new object" ;

			while( _lineReader.readln( _tempString ))
			{
				if( _tempString == "end of file" )
					break;

				if( _tempString == newobj )
				{
					auto mesh = cast(CResMesh)res;
					ReadObj( extension, mesh );
				}
			}
		}

		bool Save( char[] format, IResource res, inout Array buf ) { return false; }
		void CreateErrorResourceData( IResource res, char[] errorResName ) {}

		char[] GetResourceClass() { return CResMesh.classinfo.name; }
}
